using System;
using System.Runtime.InteropServices;
using System.Security;

namespace SharpMedia.MDX
{
    public sealed class MDXUtil
    {
        private static long tickFreq, lastTickCount, stoppedSince, lostTime = 0;
        private static bool TimerInitialized = false;
        private static double elapsed;

        private static int frameCount = 0;
        private static double fps = 0f, timeElapsed = 0f;

        public static double TimeElapsed
        {
            get { return elapsed; }
            set { elapsed = value; }
        }

        public static TimeSpan TimeSpanElapsed { get { return new TimeSpan((long)(TimeElapsed * 10000000)); } } 

        public static long CurrentTickCount { get { return lastTickCount; } }

        public static double FPS
        {
            get {
                timeElapsed += elapsed;
                frameCount++;

                if (timeElapsed >= 1)
                {
                    fps = frameCount / timeElapsed;
                    timeElapsed = 0;
                    frameCount = 0;
                }
                return fps;
            }
        }

        private static int waitCount = 0;

        public static void Wait()
        {
            if(waitCount == 0)
                stoppedSince = Timer_GetCurrentCount();
            waitCount++;
        }

        public static void Resume()
        {
            if (-- waitCount == 0 && stoppedSince != 0)
            {
                lostTime += Timer_GetCurrentCount() - stoppedSince;
                stoppedSince = 0;
            }
        }

        public static void UpdateTimer() 
        {
            if (!TimerInitialized)
            {
                if (QueryPerformanceFrequency(ref tickFreq) == false)
                {
                    throw new ApplicationException("Failed to query for the performance frequency!");
                }
                lastTickCount = Timer_GetCurrentCount();
                TimerInitialized = true;
            }

            long currTick = Timer_GetCurrentCount();
            elapsed = (currTick - lastTickCount);

            if (lostTime > 0)
            {
                elapsed -= lostTime;
                lostTime = 0;
            }

            elapsed /= (double)tickFreq;
            
            lastTickCount = currTick;
        }
        
        private static long Timer_GetCurrentCount()
        {
            long tickCount = 0;
            if (QueryPerformanceCounter(ref tickCount) == false)
            {
                throw new ApplicationException("Failed to query performance counter!");
            }
            return tickCount;
        }

        #region NativeAPI

        [SuppressUnmanagedCodeSecurity]
        [DllImport("kernel32")]
        private static extern bool QueryPerformanceFrequency(ref long PerformanceFrequency);

        [SuppressUnmanagedCodeSecurity]
        [DllImport("kernel32")]
        private static extern bool QueryPerformanceCounter(ref long PerformanceCount);

        #endregion
    }



}
